package cate.game.role.farm.adventure.task;

import cate.common.table.d.GDAdventure;
import cate.common.table.d.GDNotice;
import cate.common.table.d.GDObj;
import cate.common.table.d.GDPrivilege;
import cate.common.table.item.hero.row.HeroBaseRow;
import cate.common.table.res.adventuretask.AdventureTaskBaseRow;
import cate.common.table.role.vip.RoleVipRow;
import cate.common.util.GameResult;
import cate.game.chat.ChatContentParam;
import cate.game.client.msg.MergeMsgSender;
import cate.game.res.MixRes;
import cate.game.res.MixResItem;
import cate.game.role.Role;
import cate.game.role.RoleDependent;
import cate.game.role.bag.hero.Hero;
import cate.game.role.bag.num.NumResBag;
import cate.game.role.farm.adventure.task.msg.AdventureTaskDataResp;
import cate.game.role.farm.adventure.task.msg.ResetAccessTidsResp;
import com.fasterxml.jackson.annotation.JsonIgnore;
import easy.java.dev.note.NoteClass;
import easy.java.dev.note.NoteField;
import easy.java.practice.errorcode.EcResult;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;

import java.util.*;

@NoteClass("探索任务")
public class AdventureTask extends RoleDependent {
    @NoteField("今日已刷新次数")
    public long refreshTimes;

    @NoteField("任务")
    public List<ProcessTask> tasks;

    @NoteField("限制接取次数的任务已接取次数")
    @JsonIgnore
    private Map<Integer, Integer> acceptedLimitMap;

    @NoteField("选择一键接取的tid")
    public List<Integer> batchAccessTids;

    @Override
    public void initialize(Role role) {
        super.initialize(role);
        if (tasks == null) {
            tasks = new ArrayList<>();
        }
        if (acceptedLimitMap == null) {
            acceptedLimitMap = new HashMap<>();
        }
        if (batchAccessTids == null) {
            batchAccessTids = new ArrayList<>();
        }
        if (tasks.isEmpty()) {
            afterOpen();
        }
    }

    public void afterOpen() {
        createTasks(true, GDAdventure.REFRESH_NUM);
        initAccessTids();
    }

    private void initAccessTids() {
        for (AdventureTaskBaseRow row : role.getGame().table.adventureTask.base.getList()) {
            if (row.quality >= 3) {
                batchAccessTids.add(row.id);
            }
        }
    }

    public void addInformation(long add, MergeMsgSender sender) {
        if (add < 0) {
            role.getGame().notice.message(role, "非法数值！");
            return;
        }
        RoleVipRow vipRow = role.getBase().getVipRow();
        int maxValue = vipRow.adventureTaskValueMax;
        NumResBag numRes = role.getBag().numRes;
        long count = numRes.count(GDObj.Num.INFO_VALUE);
        long addNum = Math.min(maxValue, count + add) - count;
        if (addNum > 0) {
            numRes.addItem(GDObj.Num.INFO_VALUE, addNum, sender);
        }
    }

    public GameResult<List<Integer>> refreshTask(int refreshMode, boolean notice) {
        GameResult<List<Integer>> r = new GameResult<>();
        String consumeStr = null;
        if (refreshMode == GDAdventure.RefreshMode.FREE.getV()) {
            if (refreshTimes > 3) {
                return r.fail("刷新失败，免费次数不足");
            }
        } else if (refreshMode == GDAdventure.RefreshMode.ITEM.getV()) {
            consumeStr = GDAdventure.REFRESH_GOODS_CARD;
        } else {
            consumeStr = GDAdventure.REFRESH_GOODS_YUANBAO;
        }
        if (!StringUtils.isBlank(consumeStr)) {
            GameResult<MixResItem> result = new MixRes(consumeStr).consume(role, null);
            if (!result.ok()) {
                role.getGame().notice.tipResItem(role, result.data);
                return r.fail(result);
            }
        }
        r.data = createTasks(false, GDAdventure.REFRESH_NUM);
        if (notice) {
            noticeUpdate();
        }
        role.getHistory().action.refreshInformationTask();
        return r;
    }

    private List<Integer> createTasks(boolean init, int times) {
        if (!init) {
            refreshTimes++;
        }
        tasks.removeIf(e -> CollectionUtils.isEmpty(e.heroIds));
        int taskNum = 0;
        List<Integer> taskIds = new ArrayList<>();
        int cheatGroupId = getCheatGroupId();
        if (cheatGroupId > 0) {
            int taskId = this.random(cheatGroupId);
            if (taskId > 0) {
                tasks.add(new ProcessTask(taskId));
                taskNum ++;
                taskIds.add(taskId);
            }
        }
        while (taskNum ++ < times) {
            int group = role.getGame().table.adventureTask.group.randomGroup();
            int taskId = this.random(group);
            if (taskId == 0) {
                role.getGame().notice.message(role, "刷新失败，未能获取到正确的任务分组！");
                break;
            }
            tasks.add(new ProcessTask(taskId));
            taskIds.add(taskId);
            AdventureTaskBaseRow taskRow = role.getGame().table.adventureTask.base.get(taskId);
            if (taskRow != null && taskRow.quality >= 5) {
                sendQualityLamp();
            }
        }
        return taskIds;
    }

    //刷新出传说、神话品质情报任务时发送跑马灯
    private void sendQualityLamp() {
        List<ChatContentParam> params = new ArrayList<>();
        params.add(ChatContentParam.c(role.getBase().name));
        role.getGame().notice.lampOnline(role, GDNotice.TextId.ADVENTURE_TASK, params);
    }

    /**
     * 获取特权作弊分组
     */
    private int getCheatGroupId() {
        if (refreshTimes == GDPrivilege.REWARD_TASK_ADVANCED_REFRESH_NUM && checkPrivilege(GDPrivilege.Type.REWARD_TASK_ADVANCED)) {
            return GDPrivilege.REWARD_TASK_ADVANCED_GROUP;
        }
        if (refreshTimes == GDPrivilege.REWARD_TASK_DELUX_REFRESH_NUM && checkPrivilege(GDPrivilege.Type.SENIOR_REWARD_TASK_ADVANCED)) {
            return GDPrivilege.REWARD_TASK_DELUX_GROUP;
        }
        return -1;
    }

    private boolean checkPrivilege(int privilegeId) {
        return role.getPay().tradeMall.privilegeMall.checkValied(privilegeId);
    }

    private ProcessTask findTask(String taskUid) {
        return tasks.stream().filter(e -> StringUtils.equals(e.uid, taskUid)).findAny().orElse(null);
    }

    public GameResult<Void> acceptTask(String taskUid, List<String> heroIds) {
        GameResult<Void> r = new GameResult<>();
        ProcessTask processTask = findTask(taskUid);
        if (processTask == null) {
            return r.fail("任务不存在");
        }
        AdventureTaskBaseRow taskBaseRow = role.getGame().table.adventureTask.base.get(processTask.taskId);
        if (taskBaseRow == null) {
            return r.fail("任务不存在");
        }
        if (heroIds.size() > taskBaseRow.maxDispatchNum) {
            return r.fail("英雄数量超过任务允许上限");
        }
        if (heroIds.isEmpty()) {
            return r.fail("未上阵英雄");
        }
        List<Byte> campList = new ArrayList<>();
        if (taskBaseRow.camps != null) {
            campList.addAll(taskBaseRow.camps);
        }
        boolean starRequired = false;
        for (String heroId : heroIds) {
            //判断英雄星级、阵营和数量是否满足任务要求
            Hero hero = role.getBag().hero.getItem(heroId);
            if (hero == null) {
                return r.fail("英雄选择有误");
            }
            HeroBaseRow tpl = hero.getTpl(role.toPlayBuildContext());
            if (tpl == null) {
                return r.fail("英雄选择有误");
            }
            if (containHero(heroId)) {
                return r.fail("此英雄已被派遣");
            }
            int star = tpl.star;
            if (!starRequired && star >= taskBaseRow.heroStars) {
                starRequired = true;
            }
            campList.removeIf(a -> a == tpl.camp);
        }
        if (!starRequired) {
            return r.fail("没有英雄达到任务要求星级");
        }
        if (!campList.isEmpty()) {
            return r.fail("英雄阵营不符合任务要求");
        }
        MixRes mixRes = new MixRes(taskBaseRow.costInformation);
        GameResult<MixResItem> result = mixRes.consume(role);
        if (!result.ok()) {
            return r.fail("情报值不足，无法接取");
        }
        processTask.acceptTask(heroIds);
        if (this.containsTask(taskBaseRow.id)) {
            acceptedLimitMap.compute(taskBaseRow.id, (k, v) -> {
                if (acceptedLimitMap.containsKey(k)) {
                    v++;
                    return v;
                }
                return 1;
            });
        }
        role.getHistory().action.informationTaskGet(taskBaseRow.quality);
        noticeUpdate();
        return r;
    }

    public GameResult<Void> autoRefresh(byte quality) {
        GameResult<Void> r ;
        if ((r = autoRefreshMode(GDAdventure.RefreshMode.FREE, quality)).ok()
        || (r = autoRefreshMode(GDAdventure.RefreshMode.ITEM, quality)).ok()
        || (r = autoRefreshMode(GDAdventure.RefreshMode.M1, quality)).ok()) {
            r.message = "寻宝成功";
        }
        noticeUpdate();
        role.getGame().notice.message(role, r);
        return r;
    }

    private GameResult<Void> autoRefreshMode(GDAdventure.RefreshMode mode, byte quality) {
        GameResult<List<Integer>> freeRefreshRes = refreshTask(mode.getV(), false);
        while (freeRefreshRes.ok() && !containsQualityTask(quality, freeRefreshRes.data)) {
            freeRefreshRes = refreshTask(mode.getV(), false);
        }
        return new GameResult<Void>().f(freeRefreshRes.code, freeRefreshRes.message);
    }

    private boolean containsQualityTask(byte quality, List<Integer> tasks) {
        for (int taskId : tasks) {
            AdventureTaskBaseRow taskBaseRow = role.getGame().table.adventureTask.base.get(taskId);
            if (taskBaseRow != null && taskBaseRow.quality >= quality) {
                return true;
            }
        }
        return false;
    }

    public GameResult<Void> getTaskReward(String taskUid, int type) {
        GameResult<Void> r = new GameResult<>();
        ProcessTask task = getTask(taskUid);
        if (task == null) {
            return r.fail("任务不存在");
        }
        //是否到了完成任务的时间
        AdventureTaskBaseRow row = task.getRow(role.getGame());
        if (type == 1) {
            if (task.startTime + row.costTime > System.currentTimeMillis()) {
                long restTime = task.startTime + row.costTime - System.currentTimeMillis();
                long scale = restTime / 600000;
                if (restTime % 600000 > 0) {
                    scale ++;
                }
                MixRes cost = new MixRes(GDAdventure.INFO_TASK_ACCELERATE_COST).multiply(scale);
                EcResult<MixResItem> result = cost.consume(role);
                if (!result.ok()) {
                    role.getGame().notice.tipResItem(role, result.data);
                    return r.fail(result);
                }
            }
        } else {
            if (row.costTime > System.currentTimeMillis() - task.startTime) {
                return r.fail("目前没有可以领取的奖励");
            }
        }
        MixRes mixRes = new MixRes(row.rewardStr);
        EcResult<?> result = mixRes.addCheck(role);
        if (result.ok()) {
            mixRes.add(role);
        }
        role.getGame().notice.dialogReward(role, mixRes);
        tasks.remove(task);
        noticeUpdate();
        return r;
    }

    public void getAllTaskReward() {
        MixRes reward = new MixRes();
        List<String> taskIds = new ArrayList<>();
        // 查看已完成的任务 记录奖励
        for (ProcessTask task : tasks) {
            if (task.heroIds == null) {
                continue;
            }
            AdventureTaskBaseRow taskRow = task.getRow(role.getGame());
            if (taskRow == null) {
                continue;
            }
            long time = task.startTime + taskRow.costTime - System.currentTimeMillis();
            if (time <= 0) {
                // 记录任务的ID
                taskIds.add(task.uid);
                // 记录奖励
                reward.addList(new MixRes(taskRow.rewardStr));
            }
        }
        sendReward(taskIds, reward);
    }

    private void sendReward(List<String> taskIds, MixRes reward) {
        if (taskIds.isEmpty()) {
            role.getGame().notice.message(role, "目前没有可以领取的奖励");
            return;
        }
        // 尝试发奖励
        GameResult<?> ecResult = reward.add(role, true);
        if (!ecResult.ok()) {
            role.getGame().notice.message(role, "奖励发送失败");
            return;
        }
        // 删除任务
        tasks.removeIf(task -> taskIds.contains(task.uid));
        role.getGame().notice.dialogReward(role, reward);
        noticeUpdate();
    }

    private void resetFreeRefreshNum(boolean silence) {
        acceptedLimitMap.clear();
        refreshTimes = 0;
        if (!silence) {
            noticeUpdate();
        }
    }

    @Override
    public void onDaySpan(boolean silence) {
        resetFreeRefreshNum(silence);
    }

    private void noticeUpdate() {
        role.sendNow(new AdventureTaskDataResp(this));
    }

    private boolean containHero(String idHex) {
        for (ProcessTask task : tasks) {
            if (task.heroIds != null && task.heroIds.contains(idHex)) {
                return true;
            }
        }
        return false;
    }

    private ProcessTask getTask(String taskUid) {
        for (ProcessTask task : tasks) {
            if (StringUtils.equals(taskUid, task.uid)) {
                return task;
            }
        }
        return null;
    }

    //随机刷新情报任务
    private int random(int group) {
        return role.getGame().table.adventureTask.base.randomTask(group, acceptedLimitMap, role.getGame().getOpenDay());
    }

    private boolean containsTask(int taskId) {
        AdventureTaskBaseRow weightRow = role.getGame().table.adventureTask.base.get(taskId);
        return weightRow != null && weightRow.maxRefreshTimes > 0;
    }

    public void resetTids(Set<Integer> batchAccessTids) {
        if (batchAccessTids == null) {
            role.getGame().notice.message(role, "集合不能为空");
            return;
        }
        this.batchAccessTids.clear();
        this.batchAccessTids.addAll(batchAccessTids);
        role.getGame().notice.message(role, "已设置自动接取");
        role.sendNow(new ResetAccessTidsResp(this.batchAccessTids));
    }
}
